﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;

namespace AWS.SLAM.StructureMap
{
    public class XmlTypeProfileSection
    {
        #region Private State

        /// <summary>
        /// Regex pattern to validate Guid strings
        /// </summary>
        private static Regex _guidRegex = new Regex(@"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$", RegexOptions.Compiled);

        private XDocument _configXml;

        #endregion

        public XmlTypeProfileSection(XDocument configurationXml)
        {
            _configXml = configurationXml;
        }

        /// <summary>
        /// Gets all extra Type Profiles defined in the configuration.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<CustomTypeProfile> GetCustomTypeProfiles()
        {
            IEnumerable<CustomTypeProfile> typeProfiles = new List<CustomTypeProfile>();
            if (_configXml.Root.Element("TypeProfiles") != null)
            {
                typeProfiles =
                from typeProfile in _configXml.Root.Element("TypeProfiles").Elements("add")
                select new CustomTypeProfile
                {
                    AssemblyQualifiedTypeName = typeProfile.Attribute("AssemblyQualifiedTypeName").Value,
                    Name = typeProfile.Attribute("Name").Value,
                };
            }
            return typeProfiles;
        }

        /// <summary>
        /// Gets the Type Profile name for the given type id or name.
        /// </summary>
        /// <param name="id">Optional unique SharePoint List Guid id as string</param>
        /// <param name="typeName">Name of List or ContentType</param>
        /// <returns></returns>
        public string GetTypeProfileName(string siteCollection, string site, string id, string typeName)
        {
            Guid guidId = Guid.Empty;
            XElement selectedNode = null;

            //Selection precedence follows:
            //If ID is present and a valid, Get type that matches ID
            //If no type matches ID, Get type that has TableName matching the typeName
            //Finally, if nothing yet has been selected get the first node that has Name matching the 
            //typeName

            //Check if ID is present and valid
            if (!String.IsNullOrEmpty(id) && _guidRegex.IsMatch(id))
            {
                guidId = new Guid(id);

                selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
                                    mapping.Name == "DataMapping" &&
                                    (String.IsNullOrEmpty(siteCollection) ?
                                    (mapping.Attribute("SiteCollection") == null ||
                                    String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
                                    (mapping.Attribute("SiteCollection") != null &&
                                    mapping.Attribute("SiteCollection").Value.ToLower() == siteCollection.ToLower()))).Elements()
                                where typeNode.Attribute("ID") != null &&
                                        typeNode.Attribute("ID").Value == guidId.ToString()
                                select typeNode).DefaultIfEmpty().First();
            }

            if (selectedNode == null)
            {
                //Get node matching TableName
                selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
                                    mapping.Name == "DataMapping" &&
                                    (String.IsNullOrEmpty(siteCollection) ?
                                    (mapping.Attribute("SiteCollection") == null ||
                                    String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
                                    (mapping.Attribute("SiteCollection") != null &&
                                    mapping.Attribute("SiteCollection").Value.ToLower() == siteCollection.ToLower()))).Elements()
                                where typeNode.Attribute("TableName") != null &&
                                        typeNode.Attribute("TableName").Value == typeName
                                select typeNode).DefaultIfEmpty().First();

                //If nothing has yet been selected
                if (selectedNode == null)
                {
                    //Get node matching type
                    selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
                                        mapping.Name == "DataMapping" &&
                                        (String.IsNullOrEmpty(siteCollection) ?
                                        (mapping.Attribute("SiteCollection") == null ||
                                        String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
                                        (mapping.Attribute("SiteCollection") != null &&
                                        mapping.Attribute("SiteCollection").Value.ToLower() == siteCollection.ToLower()))).Elements()
                                    where typeNode.Attribute("Name").Value == typeName
                                    select typeNode).DefaultIfEmpty().First();
                }
            }

            string typeProfileName = selectedNode.Name.LocalName == "ContentType" ? "DefaultContentType" : "DefaultList";
            if (selectedNode.Attribute("TypeProfile") != null)
            {
                typeProfileName = selectedNode.Attribute("TypeProfile").Value;
            }

            return typeProfileName;
        }
    }
}
